﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;

namespace TresselLS
{
    class TresselSimulator
    {
        /*#
        Variable Name: memoryArray
        Module Where Defined: TresselSimulator
        Data Type: string[]
        Local or Global: Global
        Purpose: This is memory of the chip.
        #*/
        private string[] memoryArray = new string[4096];
        /*#
        Variable Name: accumulator
        Module Where Defined: TresselSimulator
        Data Type: string
        Local or Global: Global
        Purpose: This is the value of the accumulator in 24-bit hex.
        #*/
        private string accumulator = "";
        /*#
        Variable Name: baseRegister
        Module Where Defined: TresselSimulator
        Data Type: string
        Local or Global: Global
        Purpose: This is the value of the base register in 24-bit hex.
        #*/
        private string baseRegister = "";
        /*#
        Variable Name: indexRegister
        Module Where Defined: TresselSimulator
        Data Type: string
        Local or Global: Global
        Purpose: This is the value of the index register in 24-bit hex.
        #*/
        private string indexRegister = "";
        /*#
        Variable Name: lowestMemoryAddress
        Module Where Defined: TresselSimulator
        Data Type: int
        Local or Global: Global
        Purpose: This is the lowest memory address allowed to be read or written to.
        #*/
        private int lowestMemoryAddress;
        /*#
        Variable Name: highestMemoryAddress
        Module Where Defined: TresselSimulator
        Data Type: int
        Local or Global: Global
        Purpose: This is the highest memory address allowed to be read or written to.
        #*/
        private int highestMemoryAddress;
        /*#
        Variable Name: simForm
        Module Where Defined: TresselSimulator
        Data Type: SimulatorForm
        Local or Global: Global
        Purpose: Enables interaction with the simulator GUI.
        #*/
        private SimulatorForm simForm;
        /*#
        Variable Name: theStatusRegister
        Module Where Defined: TresselSimulator
        Data Type: StatusRegister
        Local or Global: Global
        Purpose: This is an instantiation of a 24-bit status register.
        #*/
        public StatusRegister theStatusRegister = new StatusRegister();
        /*#
        Variable Name: executionStartAddress
        Module Where Defined: TresselSimulator
        Data Type: int
        Local or Global: Global
        Purpose: This is the address the Location Counter will start at.
        #*/
        public int executionStartAddress;
        /*#
        Variable Name: stepPush
        Module Where Defined: TresselSimulator
        Data Type: bool
        Local or Global: Global
        Purpose: This indicates when the button to step line-by-line through the program is pushed.
        #*/
        public bool stepPush = false;
        /*#
        Variable Name: playPush
        Module Where Defined: TresselSimulator
        Data Type: bool
        Local or Global: Global
        Purpose: This indicates when the button to run through the program until told to pause, end or debug is pushed.
        #*/
        public bool playPush = false;
        /*#
        Variable Name: step
        Module Where Defined: TresselSimulator
        Data Type: bool
        Local or Global: Global
        Purpose: This indicates when the program is in step mode only simulating one instruction at a time.
        #*/
        public bool step = true;

        /*#
        Variable Name: locationCounter
        Module Where Defined: TresselSimulator
        Data Type: int
        Local or Global: Global
        Purpose: This is the locationCounter, or the address currently being simulated.
        #*/
        private int locationCounter;
        /*#
        Variable Name: endOfExecution
        Module Where Defined: TresselSimulator
        Data Type: bool
        Local or Global: Global
        Purpose: This is the true when the program has reached a halt, or an error, and the program halts execution.
        #*/
        public bool endOfExecution = false;
        /*#
        Variable Name: TresselSimulatorReference
        Module Where Defined: TresselSimulator
        Data Type: tresselLinker
        Local or Global: Global
        Purpose: a reference to linker object so that we can access information in linker easily
        #*/
        private TresselLinker tresselLinkerReference;

        public string Accumulator
        {
            #region preamble
            /*!
            Procedure Name: Accumulator
            Description: Property that allows for public setting/getting of the accumulator.
            Input Parameters: none
            Output Parameters: returns accumulator
            Error Conditions Tested: 
            Error Messages Generated:
            Original Author: RM, SH
            Procedure Creation Date: 11/20/2009
            Modification Log:
            Who: 
            When: 
            Why: 
            Coding standards met: SR
            Testing standards met: RM
            !*/
            #endregion
            get
            {
                return accumulator.PadLeft(6, '0');
            }
            set
            {
                accumulator = value;
            }
        }
        public string BaseRegister
        {
            #region preamble
            /*!
            Procedure Name: BaseRegister
            Description: Property that allows for public setting/getting of the base register.
            Input Parameters: none
            Output Parameters: returns baseRegister
            Error Conditions Tested: 
            Error Messages Generated:
            Original Author: SH, RM
            Procedure Creation Date: 11/20/2009
            Modification Log:
            Who: 
            When: 
            Why: 
            Coding standards met: SR    
            Testing standards met: RM
            !*/
            #endregion
            get
            {
                return baseRegister.PadLeft(6, '0');
            }
            set
            {
                baseRegister = value;
            }
        }
        public string IndexRegister
        {
            #region preamble
            /*!
            Procedure Name: IndexRegister
            Description: Property that allows for public setting/getting of the index register.
            Input Parameters: none
            Output Parameters: returns indexRegister
            Error Conditions Tested: 
            Error Messages Generated:
            Original Author: SH, RM
            Procedure Creation Date: 11/20/2009
            Modification Log:
            Who: 
            When: 
            Why: 
            Coding standards met: SR
            Testing standards met: RM
            !*/
            #endregion
            get
            {
                return indexRegister.PadLeft(6, '0');
            }
            set
            {
                indexRegister = value;
            }
        }
        public int LocationCounter
        {
            #region preamble
            /*!
            Procedure Name: LocationCounter
            Description: Property that allows for public setting/getting of the current location counter.
            Input Parameters: none
            Output Parameters: returns locationCounter
            Error Conditions Tested: 
            Error Messages Generated:
            Original Author: RM, SH
            Procedure Creation Date: 11/20/2009
            Modification Log:
            Who: RM, SH
            When: 11/22/2009
            Why: Added the ability to error if out of bounds.
            Coding standards met: ST
            Testing standards met: RM
            !*/
            #endregion
            get
            {
                return locationCounter;
            }
            set
            {
                if (value >= lowestMemoryAddress && value <= highestMemoryAddress)
                {
                    locationCounter = value;
                }
                else
                {
                    simForm.DisplayMessage("Location Counter out of range of program - halting execution");
                    endOfExecution = true;
                }
            }
        }
        public string[] MemoryArray
        {
            #region preamble
            /*!
            Procedure Name: MemoryArray
            Description: Property that allows for public getting of the memory for use in the form.
            Input Parameters: none
            Output Parameters: returns memoryArray
            Error Conditions Tested: 
            Error Messages Generated:
            Original Author: RM/SH
            Procedure Creation Date: 11/22/2009
            Modification Log:
            Who: 
            When: 
            Why: 
            Coding standards met: SR
            Testing standards met: RM
            !*/
            #endregion
            get
            {
                return memoryArray;
            }
        }

        public TresselSimulator(TresselLinker linkingFile, SimulatorForm simFormParam)
        {
            #region preamble
            /*!
            Procedure Name: TresselSimulator
            Description: Constructor for the simulator
            Input Parameters: TresselLinker linkingFile - the output of the linker, SimulatorForm simFormParam - so the class can interact with the form
            Output Parameters: none
            Errors Conditions Tested:
            Error Messages Generated:
            Original Author: Shawn Hall
            Procedure Creation Date: 11/18/2009
            Modification Log:
            Who: SH, RM
            When: 11/19/2009
            Why: added step/run loops to handle the running of the simulator
            Who: SH, RM
            When: 11/21/2009
            Why: Set proper lowest and highest memory addresses
            Who: SH, RM
            When: 11/22/2009
            Why: Added parameter to bring in a handle to the form
            Who: SH, RM, SR
            When: 11/24/2009
            Why: Removed while loop so that constructor can finish
            Coding standards met: SR
            Testing standards met: RM
            !*/
            #endregion
            tresselLinkerReference = linkingFile;
            simForm = simFormParam;
            LoadMemoryArray();
            /*#
            Variable Name: headerRecord
            Module Where Defined: TresselSimulator
            Data Type: string
            Local or Global: Local
            Purpose: The first line of the Linker output.
            #*/
            string headerRecord = linkingFile.HeaderRecord;
            /*#
            Variable Name: pipes
            Module Where Defined: TresselSimulator
            Data Type: char[]
            Local or Global: Local
            Purpose: A character array including the pipe character.
            #*/
            char[] pipes = {'|'};
            /*#
            Variable Name: splitHeaderRecord
            Module Where Defined: TresselSimulator
            Data Type: string[]
            Local or Global: Local
            Purpose: The first line of the Linker output split into sections to find the execution start address, etc.
            #*/
            string[] splitHeaderRecord = headerRecord.Split(pipes);
            executionStartAddress = Converter.ToInt((splitHeaderRecord)[2].Trim(), false);
            lowestMemoryAddress = Converter.ToInt((splitHeaderRecord)[4].Trim(), false);
            highestMemoryAddress = lowestMemoryAddress + Converter.ToInt((splitHeaderRecord)[3].Trim(), false);
            locationCounter = executionStartAddress;
            
        }
        public void StartSimulator()
        {
            /*!
            Procedure Name: StartSimulator
            Description: Starts the simulator
            Input Parameters: none
            Output Parameters: none
            Errors Conditions Tested:
            Error Messages Generated:
            Original Author: Shawn Hall
            Procedure Creation Date: 11/24/2009
            Modification Log:
            Who: Steve Rudy
            When: 11/29/2009
            Why: needed to call SetHalfWayConstant in this method
            Who: Steve Rudy
            When: 11/29/2009
            Why: needed to put the condition on all executions of any kind that the form cannot be closing at the time
            Coding standards met: SR
            Testing standards met: RM
            !*/
            simForm.DisplayInstructions();
            simForm.SetHalfWayConstant();
            simForm.HighlightLine(this.executionStartAddress);
            while (!endOfExecution && !simForm.stopRunning)
            {
                while (step == true && !simForm.stopRunning)
                {
                    while (!stepPush && !simForm.stopRunning && !endOfExecution)
                    {
                        System.Windows.Forms.Application.DoEvents();
                        if (playPush)
                        {
                            break;
                        }

                    }
                    System.Windows.Forms.Application.DoEvents();
                    if (endOfExecution && !simForm.stopRunning)
                    {
                        //simForm.DisplayMessage("End of execution");
                        break;
                    }
                    if (!simForm.stopRunning)
                    {
                        ExecuteInstruction();
                        stepPush = false;
                    }

                }
                if (!endOfExecution && !simForm.stopRunning)
                {
                    ExecuteInstruction();
                    stepPush = false;
                }

            }
            if (!simForm.stopRunning || endOfExecution)
            {
                simForm.DisplayMessage("End of execution");
            }
        }
        private void LoadMemoryArray()
        {
            #region preamble
            /*!
            Procedure Name: LoadMemoryArray()
            Description: Loads simulator memory array from linking file
            Input Parameters: none
            Output Parameters: none
            Errors Conditions Tested:
            Error Messages Generated:
            Original Author: Shawn Hall
            Procedure Creation Date: 11/18/2009
            Modification Log:
            Who: SH, RM
            When: 11/19/2009
            Why: Put in code to load array from file
            Who: SH, RM
            When: 11/20/2009
            Why: Changed memory bounds
            Who: SH, RM
            When: 11/21/2009
            Why: Removed finding lowest address, changed text record calls to interface with linker
            Coding standards met: SR
            Testing standards met: RM
            !*/
            #endregion
            for (int i = 0; i <= 4095; i++)
            {
                memoryArray[i] = "A80063";
            }
            /*#
            Variable Name: pipes
            Module Where Defined: LoadMemoryArray
            Data Type: char[]
            Local or Global: Local
            Purpose: A character array including the pipe character.
            #*/
            char[] pipes = { '|' };
            foreach (TextRecord aTextRecord in tresselLinkerReference.TextRecords)
            {
                memoryArray[aTextRecord.Address] = Converter.ToHex(aTextRecord.BinCode);
            }
        }
        private void ExecuteInstruction()
        {
            #region preamble
            /*!
            Procedure Name: ExecuteInstruction
            Description: Calls proper method based on instruction at current LC
            Input Parameters: none
            Output Parameters: none
            Errors Conditions Tested:
            Error Messages Generated:
            Original Author: SH, RM
            Procedure Creation Date: 11/19/2009
            Modification Log:
            Who: SH, RM
            When: 11/21/2009
            Why: Cleared status register after each run, added several instructions, changed variable names, eliminated previous
            Who: SH, RM
            When: 11/22/2009
            Why: Added several instructions, including shifts
            Who: SH, RM
            When: 11/23/2009
            Why: Changed 64 bit arithmetic instructions
            Who: SH, RM
            When: 11/24/2009
            Why: Changed ld-something-adr to do the correct thing
            Who: Group effort
            When: 11/29/2009
            Why: Random bugs (flava flav!)
            Who: Everyone
            When: 11/29/2009
            Why: Corrected our jumps
            Who: SH, GL
            When: 11/30/2009
            Why: Dividing by zero blew up, shifts and rotates could be too large, debug window was ahead
            Coding standards met: SR
            Testing standards met: RM
            !*/
            #endregion
            /*#
            Variable Name: currentInstruction
            Module Where Defined: ExecuteInstruction
            Data Type: string5
            Local or Global: Local
            Purpose: The current instruction/operation to be simulated.
            #*/
            //string currentInstruction = ((TextRecord)tresselLinkerReference.TextRecords[this.LocationCounter]).OpCode;
            string currentInstruction = tresselLinkerReference.GetOpCode(Converter.ToBin( memoryArray[this.locationCounter]).Substring(0, 6));
            /*#
            Variable Name: dontClearStatusRegister
            Module Where Defined: TresselSimulator
            Data Type: bool
            Local or Global: Local
            Purpose: A flag to know whether to clear the status register after the current instruction.
            #*/
            bool dontClearStatusRegister = false;
            simForm.HighlightLine(LocationCounter+1);
            simForm.SetDebugDisplay(Converter.ToBin(memoryArray[LocationCounter])[9].Equals('1'));
            switch (currentInstruction)
            {
                #region instructions
                case "LD-AC":
                    Accumulator = memoryArray[GetEffectiveAddress()];
                    LocationCounter++;
                    break;
                case "ST-AC":
                    memoryArray[GetEffectiveAddress()] = Accumulator;
                    LocationCounter++;
                    break;
                case "LD-IR":
                    IndexRegister = memoryArray[GetEffectiveAddress()];
                    LocationCounter++;
                    break;
                case "ST-IR":
                    memoryArray[GetEffectiveAddress()] = IndexRegister;
                    LocationCounter++;
                    break;
                case "LD-BR":
                    BaseRegister = memoryArray[GetEffectiveAddress()];
                    LocationCounter++;
                    break;
                case "ST-BR":
                    memoryArray[GetEffectiveAddress()] = BaseRegister;
                    LocationCounter++;
                    break;
                case "ADD-AC":
                    /*#
                    Variable Name: addACTemp
                    Module Where Defined: ExecuteInstruction
                    Data Type: int64
                    Local or Global: Local
                    Purpose: Contains the value of the instructed addition, before checking for overflow.
                    #*/
                    Int64 addACTemp = Convert.ToInt64(Converter.ToInt(Accumulator, true)) + Convert.ToInt64(Converter.ToInt(memoryArray[GetEffectiveAddress()], true));
                    if (!Overflow(addACTemp))
                    {
                        Accumulator = Converter.ToHex(addACTemp);
                        Accumulator = Accumulator.Substring(Accumulator.Length - 6);
                    }
                    else
                    {
                        theStatusRegister.overflowOnAdd = true;
                        dontClearStatusRegister = true;
                    }
                    LocationCounter++;
                    break;
                case "SUB-AC":
                    /*#
                    Variable Name: subACTemp
                    Module Where Defined: ExecuteInstruction
                    Data Type: int64
                    Local or Global: Local
                    Purpose: Contains the value of the instructed subtraction, before checking for overflow.
                    #*/
                    Int64 subACTemp = Convert.ToInt64(Converter.ToInt(Accumulator, true)) - Convert.ToInt64(Converter.ToInt(memoryArray[GetEffectiveAddress()], true));
                    if (!Overflow(subACTemp))
                    {
                        Accumulator = Converter.ToHex(subACTemp);
                        Accumulator = Accumulator.Substring(Accumulator.Length - 6);
                    }
                    else
                    {
                        theStatusRegister.overflowOnSubtract = true;
                        dontClearStatusRegister = true;
                    }
                    LocationCounter++;
                    break;
                case "MUL-AC":
                    /*#
                    Variable Name: mulACTemp
                    Module Where Defined: ExecuteInstruction
                    Data Type: int64
                    Local or Global: Local
                    Purpose: Contains the value of the instructed multiplication, before checking for overflow.
                    #*/
                    Int64 mulACTemp = Convert.ToInt64(Converter.ToInt(Accumulator, true)) * Convert.ToInt64(Converter.ToInt(memoryArray[GetEffectiveAddress()], true));
                    if (!Overflow(mulACTemp))
                    {
                        Accumulator = Converter.ToHex(mulACTemp);
                        Accumulator = Accumulator.Substring(Accumulator.Length - 6);
                    }
                    else
                    {
                        theStatusRegister.overflowOnMultiply = true;
                        dontClearStatusRegister = true;
                    }
                    LocationCounter++;
                    break;
                case "DIV-AC":
                    if (Converter.ToInt(memoryArray[GetEffectiveAddress()], true) == 0)
                    {
                        theStatusRegister.divideByZero = true;
                        dontClearStatusRegister = true;
                        LocationCounter++;
                        break;
                    }
                    /*#
                    Variable Name: divACTemp
                    Module Where Defined: ExecuteInstruction
                    Data Type: int64
                    Local or Global: Local
                    Purpose: Contains the value of the instructed division, before checking for overflow.
                    #*/
                    Int64 divACTemp = Convert.ToInt64(Converter.ToInt(Accumulator, true)) / Convert.ToInt64(Converter.ToInt(memoryArray[GetEffectiveAddress()], true));
                    if (!Overflow(divACTemp))
                    {
                        Accumulator = Converter.ToHex(divACTemp);
                        Accumulator = Accumulator.Substring(Accumulator.Length - 6);
                    }
                    else
                    {
                        theStatusRegister.overflowOnDivide = true;
                        dontClearStatusRegister = true;
                    }
                    LocationCounter++;
                    break;
                case "ADD-IR":
                    /*#
                    Variable Name: addIRTemp
                    Module Where Defined: ExecuteInstruction
                    Data Type: int64
                    Local or Global: Local
                    Purpose: Contains the value of the instructed addition, before checking for overflow.
                    #*/
                    Int64 addIRTemp = Convert.ToInt64(Converter.ToInt(IndexRegister, true)) + Convert.ToInt64(Converter.ToInt(memoryArray[GetEffectiveAddress()], true));
                    if (!Overflow(addIRTemp))
                    {
                        IndexRegister = Converter.ToHex(addIRTemp);
                        IndexRegister = IndexRegister.Substring(IndexRegister.Length - 6);
                    }
                    else
                    {
                        theStatusRegister.overflowOnAdd = true;
                        dontClearStatusRegister = true;
                    }
                    LocationCounter++;
                    break;
                case "SUB-IR":
                    /*#
                    Variable Name: subIRTemp
                    Module Where Defined: ExecuteInstruction
                    Data Type: int64
                    Local or Global: Local
                    Purpose: Contains the value of the instructed subtraction, before checking for overflow.
                    #*/
                    Int64 subIRTemp = Convert.ToInt64(Converter.ToInt(IndexRegister, true)) - Convert.ToInt64(Converter.ToInt(memoryArray[GetEffectiveAddress()], true));
                    if (!Overflow(subIRTemp))
                    {
                        IndexRegister = Converter.ToHex(subIRTemp);
                        IndexRegister = IndexRegister.Substring(IndexRegister.Length - 6);
                    }
                    else
                    {
                        theStatusRegister.overflowOnSubtract = true;
                        dontClearStatusRegister = true;
                    }
                    LocationCounter++;
                    break;
                case "MUL-IR":
                    /*#
                    Variable Name: mulIRTemp
                    Module Where Defined: ExecuteInstruction
                    Data Type: int64
                    Local or Global: Local
                    Purpose: Contains the value of the instructed multiplication, before checking for overflow.
                    #*/
                    Int64 mulIRTemp = Convert.ToInt64(Converter.ToInt(IndexRegister, true)) * Convert.ToInt64(Converter.ToInt(memoryArray[GetEffectiveAddress()], true));
                    if (!Overflow(mulIRTemp))
                    {
                        IndexRegister = Converter.ToHex(mulIRTemp);
                        IndexRegister = IndexRegister.Substring(IndexRegister.Length - 6);
                    }
                    else
                    {
                        theStatusRegister.overflowOnMultiply = true;
                        dontClearStatusRegister = true;
                    }
                    LocationCounter++;
                    break;
                case "DIV-IR":
                    if (Converter.ToInt(memoryArray[GetEffectiveAddress()], true) == 0)
                    {
                        theStatusRegister.divideByZero = true;
                        break;
                    }
                    /*#
                    Variable Name: divIRTemp
                    Module Where Defined: ExecuteInstruction
                    Data Type: int64
                    Local or Global: Local
                    Purpose: Contains the value of the instructed division, before checking for overflow.
                    #*/
                    Int64 divIRTemp = Convert.ToInt64(Converter.ToInt(IndexRegister, true)) / Convert.ToInt64(Converter.ToInt(memoryArray[GetEffectiveAddress()], true));
                    if (!Overflow(divIRTemp))
                    {
                        IndexRegister = Converter.ToHex(divIRTemp);
                        IndexRegister = IndexRegister.Substring(IndexRegister.Length - 6);
                    }
                    else
                    {
                        theStatusRegister.overflowOnDivide = true;
                        dontClearStatusRegister = true;
                    }
                    LocationCounter++;
                    break;
                case "AND-AC":
                    /*#
                    Variable Name: andACTop
                    Module Where Defined: ExecuteInstruction
                    Data Type: char
                    Local or Global: Local
                    Purpose: Contains the sign bit of the accumulator.
                    #*/
                    char andACTop = Converter.ToBin(Accumulator)[0];
                    Accumulator = Converter.ToBin(Converter.ToInt(Accumulator, true) & Converter.ToInt(memoryArray[GetEffectiveAddress()], true));
                    Accumulator = andACTop + Accumulator.Remove(0,1);
                    Accumulator = Converter.ToHex(Accumulator);
                    Accumulator = Accumulator.Substring(Accumulator.Length - 6);
                    LocationCounter++;
                    break;
                case "OR-AC":
                    /*#
                    Variable Name: orACTop
                    Module Where Defined: ExecuteInstruction
                    Data Type: char
                    Local or Global: Local
                    Purpose: Contains the sign bit of the accumulator.
                    #*/
                    char orACTop = Converter.ToBin(Accumulator)[0];
                    Accumulator = Converter.ToBin(Converter.ToInt(Accumulator, true) | Converter.ToInt(memoryArray[GetEffectiveAddress()], true));
                    Accumulator = orACTop +Accumulator.Remove(0, 1);
                    Accumulator = Converter.ToHex(Accumulator);
                    Accumulator = Accumulator.Substring(Accumulator.Length - 6);
                    LocationCounter++;
                    break;
                case "LAND-AC":
                    Accumulator = Converter.ToHex(Converter.ToInt(Accumulator, true) & Converter.ToInt(memoryArray[GetEffectiveAddress()], true));
                    Accumulator = Accumulator.Substring(Accumulator.Length - 6);
                    LocationCounter++;
                    break;
                case "LOR-AC":
                    Accumulator = Converter.ToHex(Converter.ToInt(Accumulator, true) | Converter.ToInt(memoryArray[GetEffectiveAddress()], true));
                    Accumulator = Accumulator.Substring(Accumulator.Length - 6);
                    LocationCounter++;
                    break;
                case "ABS-AC":
                    /*#
                    Variable Name: absACTemp
                    Module Where Defined: ExecuteInstruction
                    Data Type: int64
                    Local or Global: Local
                    Purpose: Contains the value after absolution, before checking for overflow.
                    #*/
                    Int64 absACTemp = Math.Abs(Convert.ToInt64(Converter.ToInt(Accumulator, true)));
                    if (!Overflow(absACTemp))
                    {
                        Accumulator = Converter.ToHex(absACTemp);
                        Accumulator = Accumulator.Substring(Accumulator.Length - 6);
                    }
                    else
                    {
                        theStatusRegister.overflowOnAbsolute = true;
                        dontClearStatusRegister = true;
                    }
                    LocationCounter++;
                    break;
                case "AND-IR":
                    char andIRTop = Converter.ToBin(IndexRegister)[0];
                    IndexRegister = Converter.ToBin(Converter.ToInt(IndexRegister, true) & Converter.ToInt(memoryArray[GetEffectiveAddress()], true));
                    IndexRegister = andIRTop + IndexRegister.Remove(0, 1);
                    IndexRegister = Converter.ToHex(IndexRegister);
                    IndexRegister = IndexRegister.Substring(IndexRegister.Length - 6);
                    LocationCounter++;
                    break;
                case "OR-IR":
                    /*#
                    Variable Name: orIRTop
                    Module Where Defined: ExecuteInstruction
                    Data Type: char
                    Local or Global: Local
                    Purpose: Contains the sign bit of the Index Register.
                    #*/
                    char orIRTop = Converter.ToBin(IndexRegister)[0];
                    IndexRegister = Converter.ToBin(Converter.ToInt(IndexRegister, true) | Converter.ToInt(memoryArray[GetEffectiveAddress()], true));
                    IndexRegister = orIRTop + IndexRegister.Remove(0, 1);
                    IndexRegister = Converter.ToHex(IndexRegister);
                    IndexRegister = IndexRegister.Substring(IndexRegister.Length - 6);
                    LocationCounter++;
                    break;
                case "LAND-IR":
                    IndexRegister = Converter.ToHex(Converter.ToInt(IndexRegister, true) & Converter.ToInt(memoryArray[GetEffectiveAddress()], true));
                    IndexRegister = IndexRegister.Substring(IndexRegister.Length - 6);
                    LocationCounter++;
                    break;
                case "LOR-IR":
                    IndexRegister = Converter.ToHex(Converter.ToInt(IndexRegister, true) | Converter.ToInt(memoryArray[GetEffectiveAddress()], true));
                    IndexRegister = IndexRegister.Substring(IndexRegister.Length - 6);
                    LocationCounter++;
                    break;
                case "AND-SR":
                    /*#
                    Variable Name: orACTop
                    Module Where Defined: ExecuteInstruction
                    Data Type: char
                    Local or Global: Local
                    Purpose: Contains the sign bit of the status register.
                    #*/
                    char andSRTop = theStatusRegister.ToBin()[0];
                    theStatusRegister.SetSR(Converter.ToBin(theStatusRegister.ToInt() & Converter.ToInt(memoryArray[GetEffectiveAddress()], true)));
                    theStatusRegister.SetSR(andSRTop + theStatusRegister.ToBin().Remove(0, 1));
                    LocationCounter++;
                    dontClearStatusRegister = true;
                    break;
                case "OR-SR":
                    /*#
                    Variable Name: orSRTop
                    Module Where Defined: ExecuteInstruction
                    Data Type: char
                    Local or Global: Local
                    Purpose: Contains the sign bit of the status register.
                    #*/
                    char orSRTop = theStatusRegister.ToBin()[0];
                    theStatusRegister.SetSR(Converter.ToBin(theStatusRegister.ToInt() | Converter.ToInt(memoryArray[GetEffectiveAddress()], true)));
                    theStatusRegister.SetSR(orSRTop + theStatusRegister.ToBin().Remove(0, 1));
                    LocationCounter++;
                    dontClearStatusRegister = true;
                    break;
                case "ABS-IR":
                    /*#
                    Variable Name: absIRTemp
                    Module Where Defined: ExecuteInstruction
                    Data Type: int64
                    Local or Global: Local
                    Purpose: Contains the value after absolution, before checking for overflow.
                    #*/
                    Int64 absIRTemp = Math.Abs(Convert.ToInt64(Converter.ToInt(IndexRegister, true)));
                    if (!Overflow(absIRTemp))
                    {
                        IndexRegister = Converter.ToHex(absIRTemp);
                        IndexRegister = IndexRegister.Substring(IndexRegister.Length - 6);
                    }
                    else
                    {
                        theStatusRegister.overflowOnAbsolute = true;
                        dontClearStatusRegister = true;
                    }
                    LocationCounter++;
                    break;
                case "SLA-AC":
                    /*#
                    Variable Name: slaACNumShifts
                    Module Where Defined: ExecuteInstruction
                    Data Type: int
                    Local or Global: Local
                    Purpose: Gets the number of shifts to do from GetEffectiveAddress().
                    #*/
                    if (GetEffectiveAddress() > 23)
                    {
                        theStatusRegister.shiftTooLarge = true;
                        dontClearStatusRegister = true;
                        LocationCounter++;
                        break;
                    }
                    int slaACNumShifts = GetEffectiveAddress();
                    Accumulator = Converter.ToHex(Converter.ToBin(Accumulator)[0] + Converter.ToBin(Accumulator).Remove(0, slaACNumShifts+1).PadRight(23, '0'));
                    LocationCounter++;
                    break;
                case "SRA-AC":
                    /*#
                    Variable Name: sraACNumShifts
                    Module Where Defined: ExecuteInstruction
                    Data Type: int
                    Local or Global: Local
                    Purpose: Gets the number of shifts to do from GetEffectiveAddress().
                    #*/
                    if (GetEffectiveAddress() > 23)
                    {
                        theStatusRegister.shiftTooLarge = true;
                        dontClearStatusRegister = true;
                        LocationCounter++;
                        break;
                    }
                    int sraACNumShifts = GetEffectiveAddress();
                    Accumulator = Converter.ToHex(Converter.ToBin(Accumulator)[0] + Converter.ToBin(Accumulator).Substring(1, 23 - sraACNumShifts).PadLeft(23, '0'));
                    LocationCounter++;
                    break;
                case "SLL-AC":
                    /*#
                    Variable Name: sllACNumShifts
                    Module Where Defined: ExecuteInstruction
                    Data Type: int
                    Local or Global: Local
                    Purpose: Gets the number of shifts to do from GetEffectiveAddress().
                    #*/
                    if (GetEffectiveAddress() > 23)
                    {
                        theStatusRegister.shiftTooLarge = true;
                        dontClearStatusRegister = true;
                        LocationCounter++;
                        break;
                    }
                    int sllACNumShifts = GetEffectiveAddress();
                    Accumulator = Converter.ToHex(Converter.ToBin(Accumulator).Remove(0, sllACNumShifts).PadRight(24, '0'));
                    LocationCounter++;
                    break;
                case "SRL-AC":
                    /*#
                    Variable Name: srlACNumShifts
                    Module Where Defined: ExecuteInstruction
                    Data Type: int
                    Local or Global: Local
                    Purpose: Gets the number of shifts to do from GetEffectiveAddress().
                    #*/
                    if (GetEffectiveAddress() > 23)
                    {
                        theStatusRegister.shiftTooLarge = true;
                        dontClearStatusRegister = true;
                        LocationCounter++;
                        break;
                    }
                    int srlACNumShifts = GetEffectiveAddress();
                    Accumulator = Converter.ToHex(Converter.ToBin(Accumulator).Substring(0, 24 - srlACNumShifts).PadLeft(24, '0'));
                    LocationCounter++;
                    break;
                case "RROT-AC":
                    /*#
                    Variable Name: rrotACNumShifts
                    Module Where Defined: ExecuteInstruction
                    Data Type: int
                    Local or Global: Local
                    Purpose: Gets the number of rotations to do from GetEffectiveAddress().
                    #*/
                    if (GetEffectiveAddress() > 23)
                    {
                        theStatusRegister.rotateTooLarge = true;
                        dontClearStatusRegister = true;
                        LocationCounter++;
                        break;
                    }
                    int rrotACNumShifts = GetEffectiveAddress();
                    for (int i = 0; i < rrotACNumShifts; i++)
                    {
                        Accumulator = Converter.ToHex(Converter.ToBin(Accumulator)[23] + Converter.ToBin(Accumulator).Substring(0, 23));
                    }
                    LocationCounter++;
                    break;
                case "LROT-AC":
                    /*#
                    Variable Name: lrotACNumShifts
                    Module Where Defined: ExecuteInstruction
                    Data Type: int
                    Local or Global: Local
                    Purpose: Gets the number of rotations to do from GetEffectiveAddress().
                    #*/
                    if (GetEffectiveAddress() > 23)
                    {
                        theStatusRegister.rotateTooLarge = true;
                        dontClearStatusRegister = true;
                        LocationCounter++;
                        break;
                    }
                    int lrotACNumShifts = GetEffectiveAddress();
                    for (int i = 0; i < lrotACNumShifts; i++)
                    {
                        Accumulator = Converter.ToHex(Converter.ToBin(Accumulator).Substring(1, 23) + Converter.ToBin(Accumulator)[0]);
                    }
                    LocationCounter++;
                    break;
                case "SLA-IR":
                    /*#
                    Variable Name: slaIRNumShifts
                    Module Where Defined: ExecuteInstruction
                    Data Type: int
                    Local or Global: Local
                    Purpose: Gets the number of shifts to do from GetEffectiveAddress().
                    #*/
                    if (GetEffectiveAddress() > 23)
                    {
                        theStatusRegister.shiftTooLarge = true;
                        dontClearStatusRegister = true;
                        LocationCounter++;
                        break;
                    }
                    int slaIRNumShifts = GetEffectiveAddress();
                    IndexRegister = Converter.ToHex(Converter.ToBin(IndexRegister)[0] + Converter.ToBin(IndexRegister).Remove(0, slaIRNumShifts + 1).PadRight(23, '0'));
                    LocationCounter++;
                    break;
                case "SRA-IR":
                    /*#
                    Variable Name: sraIRNumShifts
                    Module Where Defined: ExecuteInstruction
                    Data Type: int
                    Local or Global: Local
                    Purpose: Gets the number of shifts to do from GetEffectiveAddress().
                    #*/
                    if (GetEffectiveAddress() > 23)
                    {
                        theStatusRegister.shiftTooLarge = true;
                        dontClearStatusRegister = true;
                        LocationCounter++;
                        break;
                    }
                    int sraIRNumShifts = GetEffectiveAddress();
                    IndexRegister = Converter.ToHex(Converter.ToBin(IndexRegister)[0] + Converter.ToBin(IndexRegister).Substring(1, 23 - sraIRNumShifts).PadLeft(23, '0'));
                    LocationCounter++;
                    break;
                case "SLL-IR":
                    /*#
                    Variable Name: sllIRNumShifts
                    Module Where Defined: ExecuteInstruction
                    Data Type: int
                    Local or Global: Local
                    Purpose: Gets the number of shifts to do from GetEffectiveAddress().
                    #*/
                    if (GetEffectiveAddress() > 23)
                    {
                        theStatusRegister.shiftTooLarge = true;
                        dontClearStatusRegister = true;
                        LocationCounter++;
                        break;
                    }
                    int sllIRNumShifts = GetEffectiveAddress();
                    IndexRegister = Converter.ToHex(Converter.ToBin(IndexRegister).Remove(0, sllIRNumShifts).PadRight(24, '0'));
                    LocationCounter++;
                    break;
                case "SRL-IR":
                    /*#
                    Variable Name: srlIRNumShifts
                    Module Where Defined: ExecuteInstruction
                    Data Type: int
                    Local or Global: Local
                    Purpose: Gets the number of shifts to do from GetEffectiveAddress().
                    #*/
                    if (GetEffectiveAddress() > 23)
                    {
                        theStatusRegister.shiftTooLarge = true;
                        dontClearStatusRegister = true;
                        LocationCounter++;
                        break;
                    }
                    int srlIRNumShifts = GetEffectiveAddress();
                    IndexRegister = Converter.ToHex(Converter.ToBin(IndexRegister).Substring(0, 24 - srlIRNumShifts).PadLeft(24, '0'));
                    LocationCounter++;
                    break;
                case "RROT-IR":
                    /*#
                    Variable Name: rrotIRNumShifts
                    Module Where Defined: ExecuteInstruction
                    Data Type: int
                    Local or Global: Local
                    Purpose: Gets the number of rotations to do from GetEffectiveAddress().
                    #*/
                    if (GetEffectiveAddress() > 23)
                    {
                        theStatusRegister.rotateTooLarge = true;
                        dontClearStatusRegister = true;
                        LocationCounter++;
                        break;
                    }
                    int rrotIRNumShifts = GetEffectiveAddress();
                    for (int i = 0; i < rrotIRNumShifts; i++)
                    {
                        IndexRegister = Converter.ToHex(Converter.ToBin(IndexRegister)[23] + Converter.ToBin(IndexRegister).Substring(0, 23));
                    }
                    LocationCounter++;
                    break;
                case "LROT-IR":
                    /*#
                    Variable Name: lrotIRNumShifts
                    Module Where Defined: ExecuteInstruction
                    Data Type: int
                    Local or Global: Local
                    Purpose: Gets the number of rotations to do from GetEffectiveAddress().
                    #*/
                    if (GetEffectiveAddress() > 23)
                    {
                        theStatusRegister.rotateTooLarge = true;
                        dontClearStatusRegister = true;
                        LocationCounter++;
                        break;
                    }
                    int lrotIRNumShifts = GetEffectiveAddress();
                    for (int i = 0; i < lrotIRNumShifts; i++)
                    {
                        IndexRegister = Converter.ToHex(Converter.ToBin(IndexRegister).Substring(1, 23) + Converter.ToBin(IndexRegister)[0]);
                    }
                    LocationCounter++;
                    break;
                case "LDN-AC":
                    if (!Overflow(Convert.ToInt64(Converter.ToInt(memoryArray[GetEffectiveAddress()], true)) * -1))
                    {
                        Accumulator = Converter.ToHex(Convert.ToInt64(Converter.ToInt(memoryArray[GetEffectiveAddress()], true)) * -1);
                        Accumulator = Accumulator.Substring(Accumulator.Length - 6);
                    }
                    else
                    {
                        theStatusRegister.overflowOnLDN = true;
                        dontClearStatusRegister = true;
                    }
                    LocationCounter++;
                    break;
                case "HALT":
                    if (GetEffectiveAddress() == 99)
                    {
                        simForm.DisplayMessage("Attempted access of invalid memory location");
                    }
                    endOfExecution = true;
                    break;
                case "JMP-SR-GT":
                    if (theStatusRegister.ToInt() > 0)
                    {
                        LocationCounter = GetEffectiveAddress();
                    }
                    else
                    {
                        LocationCounter++;
                    }
                    break;
                case "JMP-SR-EQ":
                    if (theStatusRegister.ToInt() == 0)
                    {
                        LocationCounter = GetEffectiveAddress();
                    }
                    else
                    {
                        LocationCounter++;
                    }
                    break;
                case "JMP-SR-LT":
                    if (theStatusRegister.ToInt() < 0)
                    {
                        LocationCounter = GetEffectiveAddress();
                    }
                    else
                    {
                        LocationCounter++;
                    }
                    break;
                case "JMP":
                    LocationCounter = GetEffectiveAddress();
                    break;
                case "JMP-AC-GT":
                    if (Converter.ToInt(Accumulator, true) > 0)
                    {
                        LocationCounter = GetEffectiveAddress();
                    }
                    else
                    {
                        LocationCounter++;
                    }
                    break;
                case "JMP-AC-EQ":
                    if (Converter.ToInt(Accumulator, true) == 0)
                    {
                        LocationCounter = GetEffectiveAddress();
                    }
                    else
                    {
                        LocationCounter++;
                    }
                    break;
                case "JMP-AC-LT":
                    if (Converter.ToInt(Accumulator, true) < 0)
                    {
                        LocationCounter = GetEffectiveAddress();
                    }
                    else
                    {
                        LocationCounter++;
                    }
                    break;
                case "JMP-IR-GT":
                    if (Converter.ToInt(indexRegister, true) > 0)
                    {
                        LocationCounter = GetEffectiveAddress();
                    }
                    else
                    {
                        LocationCounter++;
                    }
                    break;
                case "JMP-IR-EQ":
                    if (Converter.ToInt(indexRegister, true) == 0)
                    {
                        LocationCounter = GetEffectiveAddress();
                    }
                    else
                    {
                        LocationCounter++;
                    }
                    break;
                case "JMP-IR-LT":
                    if (Converter.ToInt(indexRegister, true) < 0)
                    {
                        LocationCounter = GetEffectiveAddress();
                    }
                    else
                    {
                        LocationCounter++;
                    }
                    break;
                case "DISPLAY":
                    simForm.DisplayAll(lowestMemoryAddress,highestMemoryAddress );
                    LocationCounter++;
                    break;
                case "READ-NUM":
                    memoryArray[GetEffectiveAddress()] = Converter.ToHex(simForm.GetNumFromUser());
                    LocationCounter++;
                    break;
                case "READ-STR":
                    /*#
                    Variable Name: readStrTemp
                    Module Where Defined: ExecuteInstruction
                    Data Type: string
                    Local or Global: Local
                    Purpose: the string initially read in from user input.
                    #*/
                    string readStrTemp = simForm.GetStringFromUser();
                    /*#
                    Variable Name: readStrFinal
                    Module Where Defined: ExecuteInstruction
                    Data Type: int
                    Local or Global: Local
                    Purpose: Properly padded and hex converted string read in from user input.
                    #*/
                    string readStrFinal = "";
                    for (int i = 0; i < readStrTemp.Length; i++)
                    {
                        readStrFinal += Converter.ToHex((int)readStrTemp[i]);
                    }
                    while (readStrFinal.Length < 6)
                    {
                        readStrFinal += "20";
                    }
                    memoryArray[GetEffectiveAddress()] = readStrFinal;
                    LocationCounter++;
                    break;
                case "WRITE-NUM":
                    simForm.DisplayMessage(Converter.ToInt(memoryArray[GetEffectiveAddress()], true).ToString());
                    LocationCounter++;
                    break;
                case "WRITE-STR":
                    /*#
                    Variable Name: writeStrFinal
                    Module Where Defined: ExecuteInstruction
                    Data Type: int
                    Local or Global: Local
                    Purpose: Properly padded and hex converted string written to console.
                    #*/
                    string writeStrFinal = "";
                    for (int i = 0; i < 6; i+=2)
                    {
                        writeStrFinal += (char)Converter.ToInt(memoryArray[GetEffectiveAddress()].Substring(i, 2), false);
                    }
                    simForm.DisplayMessage(writeStrFinal);
                    LocationCounter++;
                    break;
                case "LD-AC-ADR":
                    Accumulator = Converter.ToHex(GetEffectiveAddress());
                    LocationCounter++;
                    break;
                case "LD-IR-ADR":
                    IndexRegister = Converter.ToHex(GetEffectiveAddress());
                    LocationCounter++;
                    break;
                case "LD-BR-ADR":
                    BaseRegister = Converter.ToHex(GetEffectiveAddress());
                    LocationCounter++;
                    break;
                default:
                    simForm.DisplayMessage("Invalid instruction encountered - halting execution");
                    endOfExecution = true;
                    break;
                #endregion
            }
            if (dontClearStatusRegister == false)
            {
                theStatusRegister.Clear();
            }
            simForm.HighlightLine(LocationCounter );
            simForm.UpdateRegisters();
        }
        private int GetEffectiveAddress()
        {
            #region preamble
            /*!
            Procedure Name: GetEffectiveAddress
            Description: Gets the effective address from the bottom 14 bits of a dataword
            Input Parameters: string addressBits - the bottom 14 bits of the dataword
            Output Parameters: none
            Errors Conditions Tested:
            Error Messages Generated:
            Original Author: SH, RM
            Procedure Creation Date: 11/20/2009
            Modification Log:
            Who: SH, RM
            When: 11/23/2009
            Why: Filled in the method
            Who: RM, LP
            When: 11/23/2009
            Why: change the check for boolean from convert to equals
            Coding standards met: SR
            Testing standards met: RM
            !*/
            #endregion
            /*#
            Variable Name: effectiveAddress
            Module Where Defined: GetEffectiveAddress
            Data Type: int
            Local or Global: Local
            Purpose: The resulting address with calculation of address flags.
            #*/
            int effectiveAddress = 0;
            /*#
            Variable Name: IRIsOn
            Module Where Defined: GetEffectiveAddress
            Data Type: bool
            Local or Global: Local
            Purpose: A check to see if the LC's contents have the IR bit turned on.
            #*/
            bool IRIsOn =( Converter.ToBin (memoryArray[LocationCounter]).PadLeft(24,'0')[6]).Equals('1');
            /*#
            Variable Name: addressField
            Module Where Defined: GetEffectiveAddress
            Data Type: string
            Local or Global: Local
            Purpose: The rightmost 11 bits of the data word.
            #*/
            string addressField = Converter.ToBin(memoryArray[LocationCounter]).PadLeft(24,'0').Substring(13);
            /*#
            Variable Name: addressFlags
            Module Where Defined: GetEffectiveAddress
            Data Type: string
            Local or Global: Local
            Purpose: Bits 11 through 13 in the data word.
            #*/
            string addressFlags = Converter.ToBin(memoryArray[LocationCounter]).PadLeft(24,'0').Substring(10, 3);
            switch (addressFlags)
            {
                case "000":
                case "100":
                    effectiveAddress = Converter.ToInt(Converter.ToHex(addressField), false);
                    if (IRIsOn)
                    {
                        effectiveAddress += Converter.ToInt(IndexRegister, false);
                    }
                    break;
                case "001":
                    effectiveAddress = Converter.ToInt(Converter.ToHex(addressField), false) + Converter.ToInt(BaseRegister, false);
                    if (IRIsOn)
                    {
                        effectiveAddress += Converter.ToInt(IndexRegister, false);
                    }
                    break;
                case "010":
                    /*#
                    Variable Name: tempAddress
                    Module Where Defined: GetEffectiveAddress
                    Data Type: int
                    Local or Global: Local
                    Purpose: A temporary location counter allowing recursion to be done for indirect addressing.
                    #*/
                    int tempAddress = LocationCounter;
                    LocationCounter = Converter.ToInt(Converter.ToHex(addressField), false);
                    effectiveAddress = GetEffectiveAddress();
                    LocationCounter = tempAddress;
                    //effectiveAddress = Converter.ToInt(Converter.ToHex(Converter.ToBin(memoryArray[Converter.ToInt(Converter.ToHex(addressField), true)]).Substring(13)), true);
                    if (IRIsOn)
                    {
                        effectiveAddress += Converter.ToInt(IndexRegister, false);
                    }
                    break;
                case "011":
                    /*#
                    Variable Name: tempAddress1
                    Module Where Defined: GetEffectiveAddress
                    Data Type: int
                    Local or Global: Local
                    Purpose: A temporary location counter allowing recursion to be done for indirect addressing.
                    #*/
                    int tempAddress1 = LocationCounter;
                    LocationCounter = Converter.ToInt(Converter.ToHex(addressField), false);
                    effectiveAddress = GetEffectiveAddress() + Converter.ToInt(BaseRegister, false);
                    LocationCounter = tempAddress1;
                    //effectiveAddress = Converter.ToInt(Converter.ToHex(Converter.ToBin(memoryArray[Converter.ToInt(Converter.ToHex(addressField), true)]).Substring(13)), true) + Converter.ToInt(BaseRegister, true);
                    if (IRIsOn)
                    {
                        effectiveAddress += Converter.ToInt(IndexRegister, false);
                    }
                    break;
                default:
                    simForm.DisplayMessage("Invalid address flags encountered - halting execution");
                    endOfExecution = true;
                    break;
            }
            return effectiveAddress;
        }
        private bool Overflow(Int64 possibleOverflow)
        {
            #region preamble
            /*!
            Procedure Name: Overflow
            Description: Checks for overflow on a hex string
            Input Parameters: Int64 possibleOverflow - 64 bit version of the overflow
            Output Parameters: none
            Errors Conditions Tested:
            Error Messages Generated:
            Original Author: SH, RM
            Procedure Creation Date: 11/22/2009
            Modification Log:
            Who: SH, RM
            When: 11/23/2009
            Why: Added the code to handle overflow
            Coding standards met: SR
            Testing standards met: RM
            !*/
            #endregion
            if (possibleOverflow < 8388607 && possibleOverflow > -8388608)
            {
                return false;
            }
            else
            {
                return true;
            }
        }
    }
}
